import axios from 'axios';
import _ from 'lodash';
import * as FetchAPI from '@CIF/API/api.js';
import Notifier from '../Utils/Notifier';
import { initError, getUniqueVersionName } from './dynamicComponentLoader';

const filterField = 'fileName'; // or filePath

// 异常: fetch failed
// const FETCH_FAILED  = (type) => `fetch [${type}] file failed, please check whether url is correct`
// 异常: remote 参数缺失
// const PARAM_UNDEFINED = (param) => `param [${param}] is required`
// 异常: remotes 数组为空
// const EMPTY_REMOTES = () => "[Remote List] is empty"

// 异常：too many component executable file
const TOO_MANY_EXECUTABLE_FILE = (versionedName) =>
	`${versionedName}组件内可执行文件数量超出限制，请检查数据库组件包文件内容！`;

/**
 * @function fetchComponentAll
 * @description 获取全部组件
 * @param { array } cpntLibEntryList 数组中 cpntLibEntry 对象包含四个属性: name, version, fileName, filePath
 * * [{
        definitionId: cpntLibrary.id,
        name: cpntLibrary.name,
        moduleName: cpntLibrary.moduleName,
        version: cpntLibrary.version,
        package: cpntLibrary.package,
      }]
 */
const fetchComponentAll = (cpntLibEntryList = []) => {
	return new Promise((resolve = () => {}, reject = () => {}) => {
		let failedReason = [];

		// 检查数组是否为空
		if (cpntLibEntryList.length === 0) {
			resolve([[], failedReason]);
			return;
		}

		// 设置 javascript 以及 css 的 request
		const requestList = [];
		const shadowRemotes = cpntLibEntryList.map((x) => {
			const versionedName = getUniqueVersionName(x);
			const pkgs = _.uniqBy(
				_.get(x, 'package')
					.filter((p) => p.fileName.startsWith(versionedName))
					.filter((y) => {
						return _.endsWith(_.get(y, 'fileName'), '.umd.js') ||
							_.endsWith(_.get(y, 'fileName'), '.css')
							? true
							: false;
					}),
				filterField
			);
			if (pkgs.length > 2) {
				failedReason.push(TOO_MANY_EXECUTABLE_FILE(versionedName));
			}
			return {
				...x,
				package: pkgs
			};
		});

		shadowRemotes
			.map((x) => x.package)
			.flatMap((x) => x)
			.forEach(({ filePath }) => {
				requestList.push(
					FetchAPI.getPackageFile(filePath, () => {
						Notifier.updateFetchingProgress();
					})
				);
			});

		Notifier.addsToCountOfRemoteLoadingAssets(requestList.length);

		const components = [];
		Promise.allSettled(requestList).then((results) => {
			const successResults = results.filter((x) => x.status === 'fulfilled').map((x) => x.value);
			const failResults = results.filter((x) => x.status === 'rejected').map((x) => x.reason);

			// 遍历, 为组件初始化 javascript 和 css 的 DOM 元素
			let cursorOfResult = 0;
			for (const sr of shadowRemotes) {
				const remoteCpnt = {
					id: sr.definitionId,
					moduleName: sr.moduleName,
					version: sr.version
				};
				sr.package.forEach((pkgFile) => {
					// javascript
					if (_.endsWith(_.get(pkgFile, 'fileName'), '.umd.js')) {
						const src = URL.createObjectURL(
							new Blob([successResults[cursorOfResult].data], {
								type: 'text/javascript'
							})
						);
						remoteCpnt.script = document.createElement('script');
						remoteCpnt.script.src = src;
						remoteCpnt.script.type = 'text/javascript';
					}
					if (_.endsWith(_.get(pkgFile, 'fileName'), '.css')) {
						// css
						remoteCpnt.cssBlob = successResults[cursorOfResult].data;
					}
					cursorOfResult = cursorOfResult + 1;
				});
				components.push(remoteCpnt);
			}
			failedReason = failedReason.concat(failResults);
			resolve([components, failedReason]);
		});
	});
};

/**
 * @function fetchComponent
 * @description 远程组件获取
 * @param { string } cpntLibEntry 组件包
 * {
      definitionId: cpntLibrary.id,
      name: cpntLibrary.name,
      moduleName: cpntLibrary.moduleName,
      version: cpntLibrary.version,
      package: cpntLibrary.package,
    }
 */
const fetchComponent = (cpntLibEntry) => {
	const requestList = [];

	const versionedName = getUniqueVersionName(cpntLibEntry);
	const pkgs = _.uniqBy(
		_.get(cpntLibEntry, 'package')
			.filter((p) => p.fileName.startsWith(versionedName))
			.filter((y) => {
				return _.endsWith(_.get(y, 'fileName'), '.umd.js') ||
					_.endsWith(_.get(y, 'fileName'), '.css')
					? true
					: false;
			}),
		filterField
	);

	if (pkgs.length > 2) {
		return Promise.reject(initError(TOO_MANY_EXECUTABLE_FILE, versionedName));
	}

	pkgs.forEach(({ filePath }) => {
		requestList.push(
			FetchAPI.getPackageFile(filePath, () => {
				Notifier.updateFetchingProgress();
			})
		);
	});

	Notifier.addsToCountOfRemoteLoadingAssets(requestList.length);

	return new Promise((resolve, reject) => {
		axios
			.all(requestList)
			.then((results) => {
				if (results.length !== pkgs.length) {
					reject('组件包文件数量与返回结果数量不一致');
					return;
				}
				// 遍历, 为组件初始化 javascript 和 css 的 DOM 元素
				const remoteCpnt = {
					id: cpntLibEntry.definitionId,
					moduleName: cpntLibEntry.moduleName,
					version: cpntLibEntry.version
				};
				let cursorOfResult = 0;
				pkgs.forEach((pkgFile) => {
					// javascript
					if (_.endsWith(_.get(pkgFile, 'fileName'), '.umd.js')) {
						const src = URL.createObjectURL(
							new Blob([results[cursorOfResult].data], {
								type: 'text/javascript'
							})
						);
						remoteCpnt.script = document.createElement('script');
						remoteCpnt.script.src = src;
						remoteCpnt.script.type = 'text/javascript';
					}
					if (_.endsWith(_.get(pkgFile, 'fileName'), '.css')) {
						// css
						remoteCpnt.cssBlob = results[cursorOfResult].data;
					}
					cursorOfResult = cursorOfResult + 1;
				});
				resolve(remoteCpnt);
			})
			.catch((err) => {
				reject(err);
			});
	});
};

export default { fetchComponentAll, fetchComponent };
